<?php
namespace Dingo\Api\Console\Command;

use ReflectionClass;
use Dingo\Blueprint\Writer;
use Illuminate\Support\Arr;
use Dingo\Api\Routing\Router;
use Dingo\Blueprint\Blueprint;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;

class Docs extends Command {
    protected $signature = 'api:docs {--name= : Name of the generated documentation}
        {--use-version= : Version of the documentation to be generated}
        {--output-file= : Output the generated documentation to a file}
        {--include-path= : Path where included documentation files are located}';
    protected $description = 'Generate API documentation from annotated controllers';

    protected $router;
    protected $blueprint;
    protected $docs;
    protected $writer;
    protected $name;
    protected $version;

    public function __construct(Router $router, Blueprint $blueprint, Writer $writer, $name, $version) {
        parent::__construct();

        $this->router = $router;
        $this->blueprint = $blueprint;
        $this->writer = $writer;
        $this->name = $name;
        $this->version = $version;
    }
    public function handle() {
        $contents = $this->blueprint->generate($this->getControllers(), $this->getDocName(), $this->getVersion(), $this->getIncludePath());

        if ($file = $this->option('output-file')) {
            $this->writer->write($contents, $file);

            return $this->info('Documentation was generated successfully.');
        }

        return $this->line($contents);
    }
    protected function getDocName() {
        $name = $this->option('name') ?: $this->name;

        if (! $name) {
            $this->comment('A name for the documentation was not supplied. Use the --name option or set a default in the configuration.');

            exit;
        }

        return $name;
    }
    protected function getIncludePath() {
        return base_path($this->option('include-path'));
    }
    protected function getVersion() {
        $version = $this->option('use-version') ?: $this->version;

        if (! $version) {
            $this->comment('A version for the documentation was not supplied. Use the --use-version option or set a default in the configuration.');

            exit;
        }

        return $version;
    }
    protected function getControllers() {
        $controllers = new Collection;

        foreach ($this->router->getRoutes() as $collections) {
            foreach ($collections as $route) {
                if ($controller = $route->getControllerInstance()) {
                    $this->addControllerIfNotExists($controllers, $controller);
                }
            }
        }

        return $controllers;
    }
    protected function addControllerIfNotExists(Collection $controllers, $controller) {
        $class = get_class($controller);

        if ( $controllers->has($class) ) return;

        $reflection = new ReflectionClass($controller);

        $interface = Arr::first($reflection->getInterfaces(), function ($key, $value) {
            return ends_with($key, 'Docs');
        });

        if ($interface) {
            $controller = $interface;
        }

        $controllers->put($class, $controller);
    }
}
